﻿using System;
using System.Data;
using System.Data.Entity;
using System.Linq;
using Xoohoo.Extensions;
using Xoohoo.Models.InputModels;
using XM = Xoohoo.Models;
using Xoohoo.Repositories.SqlServerEF.Entities;
using System.Linq.Expressions;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Collections;

namespace Xoohoo.Repositories.SqlServerEF
{
    public class UserRepository : RepositoryBase<User>, IUserRepository
    {
        private readonly Expression<Func<User, XM.User>> _selector;

        public UserRepository()
        {
            _selector = u => new XM.User
            {
                UserID = u.UserID,
                Username = u.Username,
                DisplayName = u.DisplayName,
                Email = u.Email,
                Password = u.Password,
                CreationDate = u.CreationDate,
                Status = (XM.UserStatus)u.Status,
                UserGroup = new XM.UserGroupBasic
                            {
                                UserGroupID = u.UserGroup.UserGroupID,
                                UserGroupName = u.UserGroup.UserGroupName,
                                IsSystem = u.UserGroup.IsSystem
                            },
                Roles = from ur in u.Roles
                        select new XM.RoleBasic
                        {
                            RoleID = ur.RoleID,
                            RoleName = ur.RoleName,
                            IsSystem = ur.IsSystem,
                            DisplayOrder = ur.DisplayOrder
                        },
                Permissions = from up in u.Permissions
                                  select new XM.PermissionBasic
                                  {
                                      ModuleName = up.ModuleName,
                                      PermissionID = up.PermissionID,
                                      PermissionName = up.PermissionName
                                  },
                UserGroupRoles = from ugr in u.UserGroup.Roles
                                 select new XM.RoleBasic
                                 {
                                     RoleID = ugr.RoleID,
                                     RoleName = ugr.RoleName,
                                     IsSystem = ugr.IsSystem,
                                     DisplayOrder = ugr.DisplayOrder
                                 },

            };
        }

        #region IUserRepository 成员

        public XM.User GetItem(string name,XM.UserStatus status)
        {
            XM.User user = DbSet.Where(m => m.Status == (int)status).Select(_selector).FirstOrDefault(m => m.Username == name);
            ProjectUser(user);
            return user;
        }

        public XM.User GetItem(int userID)
        {
            XM.User user = DbSet.Select(_selector).FirstOrDefault(m => m.UserID == userID);
            ProjectUser(user);
            return user;
        }

        public XM.User GetItem(string name)
        {
            XM.User user = DbSet.Select(_selector).FirstOrDefault(m => m.Username == name);
            ProjectUser(user);
            return user;
        }

        public bool IsExists(string name)
        {
            return DbSet.Any(m=>m.Username == name);
        }

        public bool IsExists(int userID)
        {
            return DbSet.Any(m => m.UserID == userID);
        }

        public bool ValidateUser(int userID, string name)
        {
            return DbSet.Any(m => m.UserID != userID&&m.Username==name);
        }

        public XM.IPagedList<XM.UserBasic> GetList(XM.UserSearchCriteria criteria, XM.PagingInfo pageingInfo)
        {
            Expression<Func<User, XM.UserBasic>> selector = u => new XM.UserBasic
                {
                    UserID = u.UserID,
                    Username = u.Username,
                    DisplayName = u.DisplayName,
                    Email = u.Email,
                    CreationDate = u.CreationDate,
                    Status = (XM.UserStatus)u.Status,
                    UserGroup = new XM.UserGroupBasic
                                {
                                    UserGroupID = u.UserGroup.UserGroupID,
                                    UserGroupName = u.UserGroup.UserGroupName,
                                    IsSystem = u.UserGroup.IsSystem
                                },
                };

            IQueryable<User> list = DbSet;
            if (criteria != null)
            {
                if (criteria.UserGroupID.HasValue)
                    list = list.Where(m=>m.UserGroupID==criteria.UserGroupID.Value);
                if (criteria.Status.HasValue)
                {
                    int status = (int)criteria.Status.Value;
                    list = list.Where(m => m.Status == status);
                }
                if (!criteria.Keyword.IsNullOrWhiteSpace())
                    list = list.Where(m=>m.Username.Contains(criteria.Keyword)||m.DisplayName.Contains(criteria.Keyword));
            }
            int count = list.Count();
            
            return new XM.PagedList<XM.UserBasic>(list
                .OrderBy(m=>m.CreationDate)
                .Skip(pageingInfo.Index * pageingInfo.Size)
                .Take(pageingInfo.Size)
                .Select(selector)
                .ToList(),
                pageingInfo.Index, 
                pageingInfo.Size, 
                count);
        }

        public XM.User Save(UserInput userInput)
        {
            User userToSave;
            if (userInput.UserID.HasValue)
            {
                userToSave = DbSet.FirstOrDefault(m => m.UserID == userInput.UserID.Value);
                if (userToSave == null) return null;

            }
            else
            {
                userToSave = DbSet.Create();
                DbSet.Add(userToSave);
                userToSave.Status = (int)XM.UserStatus.Normal;
                userToSave.CreationDate = DateTime.Now;
            }
            userToSave.UserGroupID = userInput.UserGroupID;
            userToSave.Username = userInput.Username;
            userToSave.DisplayName = userInput.DisplayName;
            userToSave.Email = userInput.Email;

            #region 用户角色
            //移除项
            if (!userToSave.Roles.IsNullOrEmpty())
            {
                if (!userInput.Roles.IsNullOrEmpty())
                {
                    List<Role> roleToRemove = (from p in userToSave.Roles
                                                           where !userInput.Roles.Contains(p.RoleID)
                                                           select p).ToList();
                    for (int i = 0; i < roleToRemove.Count; i++)
                        userToSave.Roles.Remove(roleToRemove[i]);
                }
                else
                {
                    userToSave.Roles.Clear();
                }
            }
            //添加项
            if (!userInput.Roles.IsNullOrEmpty())
            {
                //要添加的ID集
                List<Guid> roleIDToAdd = (from p in userInput.Roles
                                          where !userToSave.Roles.Any(m => m.RoleID == p)
                                          select p).ToList();

                //要添加的项
                List<Role> roleToAdd = (from p in DB.Roles
                                        where roleIDToAdd.Contains(p.RoleID)
                                                    select p).ToList();
                foreach (var item in roleToAdd)
                    userToSave.Roles.Add(item);

            }
            #endregion

            #region 用户权限
            //移除项
            if (!userToSave.Permissions.IsNullOrEmpty())
            {
                if (!userInput.Permissions.IsNullOrEmpty())
                {
                    List<Permission> permissionToRemove = (from p in userToSave.Permissions
                                                           where !userInput.Permissions.Contains(p.PermissionID)
                                                           select p).ToList();
                    for (int i = 0; i < permissionToRemove.Count; i++)
                        userToSave.Permissions.Remove(permissionToRemove[i]);
                }
                else
                {
                    userToSave.Permissions.Clear();
                }
            }
            //添加项
            if (!userInput.Permissions.IsNullOrEmpty())
            {
                //要添加的ID集
                List<Guid> permissionIDToAdd = (from p in userInput.Permissions
                                                where !userToSave.Permissions.Any(m => m.PermissionID == p)
                                                select p).ToList();

                //要添加的项
                List<Permission> permissionToAdd = (from p in DB.Permissions
                                                    where permissionIDToAdd.Contains(p.PermissionID)
                                                    select p).ToList();
                foreach (var item in permissionToAdd)
                    userToSave.Permissions.Add(item);

            }
            #endregion

            DB.SaveChanges();

            return GetItem(userToSave.Username);
        }

        public bool SetPassword(int userID, string password)
        {
            var  user = DbSet.FirstOrDefault(m => m.UserID == userID);
            if (user == null)
                return false;

            user.Password = password;
            DB.SaveChanges();

            return true;
        }

        public bool Remove(int userID)
        {
            User user = DbSet.FirstOrDefault(m => m.UserID == userID);
            if (user == null) return false;
            string sql = "Delete UserRoleRelationShip Where UserID=@UserID";
            DB.Database.ExecuteSqlCommand(sql,new SqlParameter("UserID",userID));

            sql = "Delete UserPermissionRelationShip Where UserID=@UserID";
            DB.Database.ExecuteSqlCommand(sql,new SqlParameter("UserID",userID));

            sql = "Delete UserModuleData Where UserID=@UserID";
            DB.Database.ExecuteSqlCommand(sql,new SqlParameter("UserID",userID));

            DbSet.Remove(user);
            DB.SaveChanges();

            return true;
        }

        public bool ChangeStatus(int userID, XM.UserStatus status)
        {
            User user = DbSet.FirstOrDefault(m => m.UserID == userID);
            if (user == null) return false;
            user.Status = (int)status;
            DB.SaveChanges();
            return true;
        }

        #endregion

        #region Private Methods

        private void ProjectUser(XM.User user)
        {
            if (user == null) return;
            SetIdentity(user);
            SetRolePermissions(user);
            SetUserGroupRolePermissions(user);
        }
        private void SetIdentity(XM.User user)
        {
            user.Identity = new Xoohoo.Infrastructure.UserIdentity(null, true, user.Username);
        }
        private void SetRolePermissions(XM.User user)
        {
            if (user.Roles.IsNullOrEmpty()) return;
            var userRoles = user.Roles.Select(m => m.RoleID);
            var permissions = from r in DB.Roles
                              from p in r.Permissions
                              where userRoles.Contains(r.RoleID)
                              select new XM.PermissionBasic
                              {
                                  ModuleName = p.ModuleName,
                                  PermissionID = p.PermissionID,
                                  PermissionName = p.PermissionName
                              };
            user.RolePermissions = permissions.ToList();
        }
        private void SetUserGroupRolePermissions(XM.User user)
        {
            var permissions = from ug in DB.UserGroups
                              from r in ug.Roles
                              from p in r.Permissions
                              where ug.UserGroupID == user.UserGroup.UserGroupID
                              select new XM.PermissionBasic
                              {
                                  ModuleName = p.ModuleName,
                                  PermissionID = p.PermissionID,
                                  PermissionName = p.PermissionName
                              };
            user.UserGroupRolePermissions = permissions.ToList();
        }

        #endregion

    }
}
